#!/bin/env ruby

#=Classe Case
#La classe Case (classe abstraite) permet la création d'une Case dans le jeu "Legend of Ouf".
#
#=Variables de classes
#[@@depensesFranchissable] Une table de hachage des differents terrains franchissables possible. 
#[@@depensesObstacle] Une table de hachage des differents terrains infranchissables possible.
#[@@depensesTerrain] Une table de hachage 
#
#=Variables d'instance
#[@typeterrain] Type de terrain de la Case.
#[@visible] Indique si la Case est visible ou non.
#[@nord] Case au dessus de la Case actuel.
#[@sud] Case en dessous de la Case actuel.
#[@est] Case a droite de la Case actuel.
#[@ouest] Case a gauche de la Case actuel.
#[@obstacle] Indique si la Case est un obstacle.
class Case
    # Variables d'instances
    @typeTerrain
    @visible
    @nord
    @sud
    @est
    @ouest
    @obstacle
    
	# Variables de classes
	@@depensesFranchissable	= {
		"foret"		=> 12,
		"herbe"		=> 4,
		"plaine"	=> 2,
		"route"		=> 2,
		"sable"		=> 6
	}
	
	@@depensesObstacle	= {
		"mont"	=> -1
	}
	
	@@depensesTerrain	= @@depensesFranchissable.merge(@@depensesObstacle).merge({"aucun" => 0 })

	$terrainsFranchissable	= @@depensesFranchissable.keys
	$terrainsObstacle	= @@depensesObstacle.keys
	$terrains		= @@depensesTerrain.keys
    
	# Méthode new privatisé
    private_class_method :new
	
	# Méthode Case.creer. Prend en paramatre dans l'ordre: un type de terrain, un boolean, un type Case, un type Case, un type Case, un type Case et un boolean.
    # Méthode de classe permettant la création d'instance de Case remplacant le new.
    def Case.creer(typeTerrain,visible,nord,sud,est,ouest,obstacle)
        new(typeTerrain,visible,nord,sud,est,ouest,obstacle)
    end
    
	# Méthode initialize.
    # Prend 7 paramétres.
    def initialize(typeTerrain,visible,nord,sud,est,ouest,obstacle)
        @typeTerrain,@visible,@nord,@sud,@est,@ouest,@obstacle=typeTerrain,visible,nord,sud,est,ouest,obstacle
	if ! $terrains.include?(typeTerrain)
       		@typeTerrain = "aucun"
        end
        return nil
    end
   
    # Méthode visible?. Aucun parametre.
    # Renvoie vrai si la Case est visible.
    def visible?()
       return @visible
    end
       
    # Méthode setVisible. Un parametre boolean.
    # Change la visibilité de la Case.
    def setVisible(bool)
        return @visible=bool
    end
    
	# Méthode obtenirTypeTerrain. Aucun parametre.
    # Retourne le type de terrain de cette case.
    def obtenirTypeTerrain()
        return @typeTerrain
    end
    
	# Méthode obstacle?. Aucun parametre.
    # Retourne vrai si la Case est un obstacle.
    def obstacle?()
        return @obstacle
    end
    
	# Méthode caseVoisine?. Un parametre de type Case.
    # Retourne vrai si la Case mis en parametre est une Case voisine de cette Case.
    def caseVoisine?(b)
        if(b.equal?(@nord) || b.equal?(@sud) || b.equal?(@est) || b.equal?(@ouest))
            return true
        else
            return false
        end
    end
    
	# Méthode getNord. Aucun parametre.
    # Retourne la Case Nord de cette Case.
    def getNord()
     return @nord
    end
	
	# Méthode getSud. Aucun parametre.
    # Retourne la Case Sud de cette Case.
    def getSud()
        return @sud
    end
	
	# Méthode getEst. Aucun parametre.
    # Retourne la Case Est de cette Case.
    def getEst()
        return @est
    end
	
	# Méthode getOuest. Aucun parametre.
    # Retourne la Case Ouest de cette Case.
    def getOuest()
        return @ouest
    end
	
	# Méthode setNord. Un parametre de type Case.
    # Remplace la Case Nord de cette Case.
    def setNord(v)
       @nord=v
       return 0
    end
	
	# Méthode setSud. Un parametre de type Case.
    # Remplace la Case Sud de cette Case.
    def setSud(v)
       @sud=v
       return 0
    end
	
	# Méthode setEst. Un parametre de type Case.
    # Remplace la Case Est de cette Case.
    def setEst(v)
       @est=v
       return 0
    end
	
	# Méthode setOuest. Un parametre de type Case.
    # Remplace la Case Ouest de cette Case.
    def setOuest(v)
       @ouest=v
       return 0
    end
    
end


#=Classe CaseObstacle
#La classe CaseObstacle permet la création d'une case de type obstacle dans le jeu "Legend of Ouf". (Cette classe hérite de Case).
class CaseObstacle < Case
	# Méthode CaseObstacle.creer. Prend en paramatre dans l'ordre: un type de terrain, un boolean, un type Case, un type Case, un type Case et un type Case.
    # Méthode de classe permettant la création d'instance de Case remplacant le new.
    def CaseObstacle.creer(typeTerrain,visible,nord,sud,est,ouest)
		if(@@depensesObstacle[typeTerrain]!=-1)
			raise "Erreur, le type de terrain est de type Franchissable mais l'objet est de type non franchissable !";
		end
			new(typeTerrain,visible,nord,sud,est,ouest,true)
    end
end

#=Classe CaseFranchissable
#La classe CaseFranchissable permet la création d'une case de type franchissable dans le jeu "Legend of Ouf". (Cette classe hérite de Case).
#
#=variables d'instance
#[@objets] Un tableau d'Objet.
#[@heros] Contient ou pas un Heros.
#[@pnj] Contient ou pas un PNJ.
#[@depenseEnergie] Représente l'energie qu'il faut pour franchir la Case (dépend du type de terrain).
#[@orJeu] Représente l'or du Jeu.
class CaseFranchissable < Case
    # Variables d'instances
    @objets
    @heros
    @pnj
    @depenseEnergie
    @orJeu
    
	# Méthode CaseFranchissable.creer. Prend en paramatre dans l'ordre: un type de terrain, un boolean, un type Case, un type Case, un type Case, un type Case et un boolean.
    # Méthode de classe permettant la création d'instance de Case remplacant le new.
    def CaseFranchissable.creer(typeTerrain,visible,nord,sud,est,ouest,orJeu)
        new(typeTerrain,visible,nord,sud,est,ouest,orJeu)
    end
    
	# Méthode initialize.
    # Prend 7 paramétres.
    def initialize(typeTerrain,visible,nord,sud,est,ouest,orJeu)
        super(typeTerrain,visible,nord,sud,est,ouest,false)
        
    	@objets		= Array.new()
    	@pnj		= nil
    	@heros		= nil
        @depenseEnergie	= @@depensesTerrain[typeTerrain]
        @orJeu		= orJeu
        if(@depenseEnergie < 0)
            raise "Erreur, le type de terrain pose probleme (terrain non franchissable sur case franchissable) !"
        end
    end
    
    # Méthode getHeros. Aucun parametre.
    # Retourne le Heros présent dans la case.
    def getHeros
        return @heros
    end

	# Méthode getPnj. Aucun parametre.
    # Retourne le PNJ présent dans la case.
    def getPnj
        return @pnj
    end

	# Méthode getOr. Aucun parametre.
    # Retourne l'or présent dans la case. Ne vide pas l'or de la case.
    def getOr
        return @orJeu
    end

	# Méthode getObjets. Aucun parametre.
    # Retourne la liste d'Objet (attention retourne la référence). Deprecated, voir dans CaseFranchissable obtenirObjet!.
    def getObjets
        return @objets
    end
    
	# Méthode setHeros. Un parametre de type Heros.
    # Remplace le Heros présent dans la case (si il y en a un) par le parametre.
    def setHeros(v)
        @heros=v
        return nil
    end
    
	# Méthode setPnj. Un parametre de type PNJ.
    # Remplace le PNJ présent dans la case (si il y en a un) par le parametre.
    def setPnj(v)
        @pnj=v
        return nil
    end
    
	# Méthode setOr. Un parametre de type Integer.
    # Remplace l'or présent dans la case (identique a ajouterOr).
    def setOr(v)
        @orJeu=v
        return nil
    end
    
	# Méthode setObjets. Un parametre de type tableau.
    # Remplace la liste d'objet présent dans la case par le parametre.
    def setObjets(v)
        @objets=v
        return nil
    end

	# Méthode deplacerJoueur. Un parametre de type Case.
    # Déplace le joueur a la case mise en parametre.
	def deplacerHeros(aCase)
		if(!aCase.obstacle?())
			depenserEnergie()
			aCase.setHeros(@heros)
			@heros.setCase(aCase)
			@heros=nil
		end
	end

	# Méthode deplacerPNJ. Un parametre de type Case.
    # Déplace le PNJ a la case mise en parametre.
	def deplacerPNJ(aCase)
		if(!aCase.obstacle?())
			aCase.setPnj(@pnj)
			@pnj.setCase(aCase)
			@pnj=nil
		end
	end

	# Méthode depenseEnergie(). Aucun parametre.
    # Diminue l'énergie de l'Hero pour franchir le type de terrain de cette case.
    def depenserEnergie()
	@heros.diminuerEnergie(@depenseEnergie)
    end
    
	# Méthode verifierHerosEtPNJ?. Aucun parametre.
    # Verifie si un Hero est present en meme temps qu'un PNJ.
    def verifierHerosEtPNJ?()
	if(@pnj!=nil && @heros!=nil)
		return true
	end
	return false
    end

	# Méthode presentObjet?. Aucun parametre.
    # Retourne vrai si il y a une liste d'Objet present.
    def presentObjet?
	return (!@objets.empty?)
    end

    # Méthode obtenirObjet!. Aucun parametre.
    # Retourne la liste d'Objet et vide la liste present dans la Case.
    def obtenirObjet!
    	objets=@objets.dup
        @objets.clear()
        return objets
    end
    
    # Méthode obtenirOr!. Aucun parametre.
    # Retourne l'or present sur la case.   
    def obtenirOr!
        orJeu=@orJeu
        @orJeu=0
        return orJeu
    end
    
	# Méthode presentOr?. Aucun parametre.
    # Retourne vrai si il y a de l'or present sur la case.   
	def presentOr?
		if(@orJeu==0)
			return false
		end
		return true
	end
	
    # Méthode ajouterObjet. Un parametre de type Objet.
    # Ajoute un Objet a la liste d'Objet de la Case.
    def ajouterObjet(b)
        @objets.push(b)
        return nil
    end

    # Méthode ajouterOr. Un parametre de type Integer.
    # Ajoute de l'or a la Case.
    def ajouterOr(b)
        @orJeu=b
        return nil
    end

end
